package com.fuhailiu.opengl.widget;

import java.io.IOException;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES30;
import android.opengl.GLUtils;

import com.fuhailiu.opengl.utils.BitmapUtil;
import com.fuhailiu.opengl.utils.GlUtil;
import com.fuhailiu.opengl.utils.LogUtil;
import com.fuhailiu.opengl.utils.MatrixUtil;
import com.fuhailiu.opengl.utils.ShaderUtil;
import com.fuhailiu.opengl.view.GLView;

public class GLTexture2D extends GLView {

	private final String TAG = getClass().getSimpleName();

	public final float x = 0.4f;
	public final float y = 0.4f;

	// 顶点坐标数据
	private float vertexCoords[] = new float[] { 
			-x, -y, 0f, // 0 bottom left
			x, -y, 0f, // 1 bottom right
			-x, y, 0f, // 2 top left
			x, y, 0f, // 3 top right
	};

	// 纹理坐标数据
	private float textureCoords[] = new float[] { 
			0.0f, 1.0f, 0f, // 0 bottom left
			1.0f, 1.0f, 0f, // 1 bottom right
			0.0f, 0.0f, 0f, // 2 top left
			1.0f, 0.0f, 0f, // 3 top right
	};

	// 顶点坐标数据缓冲
	private FloatBuffer mBufferVertex;
	// 纹理坐标数据缓冲
	private FloatBuffer mBufferTexture;

	// 自定义渲染管线程序id
	private int handleProgram;
	// 顶点位置属性引用id
	private int handlePosition;
	// 纹理坐标属性引用id
	private int handleTextureCoord;
	// 总变换矩阵引用id
	private int handleMVPMatrix;

	private int mTextureId;
	public volatile float mTranslateX = 0;
	public volatile float mTranslateY = 0;

	public GLTexture2D(Context context) {
		super(context);
		initVertexData();
		initTexture(context);
		initShader();
	}

	private void initVertexData() {
		mBufferVertex = GlUtil.createFloatBuffer(vertexCoords);
		mBufferTexture = GlUtil.createFloatBuffer(textureCoords);
	}

	private final String PATH = "texture_2d.jpg";

	private void initTexture(Context context) {
		int[] textureIds = new int[1];
		GLES30.glGenTextures(1, textureIds, 0);

		int textureId = textureIds[0];
		GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
		GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
		GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
		GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
		GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
		Bitmap bitmap = null;
		try {
			bitmap = BitmapUtil.decodeBitmap(context.getAssets().open(PATH), 640, 480);
		} catch (IOException e) {
			e.printStackTrace();
		}
		GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
		bitmap.recycle();

		mTextureId = textureId;
	}

	private static final String VERTEX_SHADER = 
					"uniform mat4 uMVPMatrix;\n" + 
					"attribute vec3 aPosition;\n" + 
					"attribute vec3 aTextureCoord;\n" + 
					"varying vec2 vTextureCoord;\n" + 
					"void main() {\n" + 
					"    gl_Position = uMVPMatrix * vec4(aPosition, 1);\n" + 
					"    vTextureCoord = aTextureCoord.xy;\n" + 
					"}\n";

	private static final String FRAGMENT_SHADER = 
						"precision mediump float;\n" + 
						"varying vec2 vTextureCoord;\n" + 
						"uniform sampler2D sTexture;\n" + 
						"void main() {\n" + 
						"    gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + 
						"}\n";

	private void initShader() {
		LogUtil.LogD(TAG, "initShader   <---");

		// 基于顶点着色器与片元着色器创建程序
		handleProgram = ShaderUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
		// 获取程序中顶点位置属性引用id
		handlePosition = GLES30.glGetAttribLocation(handleProgram, "aPosition");
		// 获取程序中纹理坐标引用id
		handleTextureCoord = GLES30.glGetAttribLocation(handleProgram, "aTextureCoord");
		// 获取程序中总变换矩阵引用id
		handleMVPMatrix = GLES30.glGetUniformLocation(handleProgram, "uMVPMatrix");

		LogUtil.LogD(TAG, "initShader   --->");
	}

	@Override
	public void release() {
		super.release();
		GLES30.glDeleteTextures(1, new int[] { mTextureId }, 0);
	}
	
	private final int sizeOfVertexPosition = 3;
	private final int sizeOfVertexTexture = 3;

	public void draw(GL10 gl) {
		// 指定逆时针为“前面”
		GLES30.glFrontFace(GLES30.GL_CCW);
		// 启用裁剪
		GLES30.glEnable(GLES30.GL_CULL_FACE);
		// 裁剪“后面”
		GLES30.glCullFace(GLES30.GL_BACK);

		// 保存当前矩阵
		MatrixUtil.pushMatrix();
		MatrixUtil.translate(mTranslateX, mTranslateY, 0);

		// 使用shader程序
		GLES30.glUseProgram(handleProgram);
		GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
		GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId);

		// 指定顶点位置数据
		GLES30.glVertexAttribPointer(handlePosition, sizeOfVertexPosition, GLES30.GL_FLOAT, false, sizeOfVertexPosition * GlUtil.SIZE_OF_FLOAT, mBufferVertex);
		// 指定纹理坐标数据
		GLES30.glVertexAttribPointer(handleTextureCoord, sizeOfVertexTexture, GLES30.GL_FLOAT, false, sizeOfVertexTexture * GlUtil.SIZE_OF_FLOAT, mBufferTexture);
		// 指定变换矩阵
		GLES30.glUniformMatrix4fv(handleMVPMatrix, 1, false, MatrixUtil.getMVPMatrix(), 0);
		// 启用顶点位置数组
		GLES30.glEnableVertexAttribArray(handlePosition);
		// 启用纹理坐标数组
		GLES30.glEnableVertexAttribArray(handleTextureCoord);
		// 绘制三角形
		GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
		// 禁用顶点位置数组
		GLES30.glDisableVertexAttribArray(handleTextureCoord);
		// 禁用顶点颜色数组
		GLES30.glDisableVertexAttribArray(handlePosition);

		// 恢复矩阵
		MatrixUtil.popMatrix();

		// 禁用背面裁剪
		GLES30.glDisable(GLES30.GL_CULL_FACE);
	}

}
